import { UserModel } from "../../../../account_server/model/UserModel";
import { HallServer_SocketMsgHandler } from "../../../../hall_server/HallServer_SocketMsgHandler";
import { Config } from "../../../config/Config";
import { JhaoProto } from "../../../lib/net/protobuf/jhaoproto";
import { ProtoManager } from "../../../lib/net/protobuf/ProtoManager";
import DateUtil from "../../utils/DateUtil";
import { EventManager } from "../../utils/EventManager";
import { Logger } from "../../utils/Logger";
import { SocketClientMsgHandler } from "./SocketClientMsgHandler";
import { SocketConnectionManager } from "./SocketConnectionManager";

const Check_Time_Inteval: number = 1000 * 5;
const NoMsg_Time_Inteval: number = 1000 * 30;
export class SocketConnection {

    public static ReadyState = {
        Open: 1,
        Close: 3
    }

    private static id: number = 0;

    public id: number = 0;
    private connection: any;
    private isDestroyed: boolean = false;
    public ip: string;
    public isClosing: boolean;
    private gotoCloseTime: number = 0;
    private connectTime: number = 0

    private timeCount: number = 0
    private lastRecvMsgTime: number = 0

    public account: string;
    public user: UserModel
    public isInternalServer: boolean = false;

    constructor(connection, ip: string) {
        EventManager.instance.on(Config.Event_Config.Timer, this.onTimer, this)
        this.connection = connection;
        SocketConnection.id++;
        this.ip = ip
        this.id = SocketConnection.id;
        this.connectTime = DateUtil.now()
        this.initConnect();
    }

    private initConnect() {
        this.isDestroyed = false;
        this.isClosing = false;
        this.connection.on('close', () => {
            Logger.log('SocketConnection disconnected', this.account);
            this.destroy()
        });

        this.connection.on('message', (data) => {
            this.lastRecvMsgTime = DateUtil.now()
            this.onClientMsgHandler(data)
        });
    }

    private onTimer(now: number) {
        if ((now - this.timeCount) >= Check_Time_Inteval) {
            this.timeCount = now
            if (!this.isLogin()) { //连接后很久不登录释放连接 
                if (now - this.connectTime >= 1000 * 60) {
                    this.destroy()
                    return false
                }
            } else {
                if (!this.isInternalServer && this.lastRecvMsgTime > 0 && (now - this.lastRecvMsgTime) >= NoMsg_Time_Inteval) {
                    this.lastRecvMsgTime = 0
                    this.checkDestroyAccountConnect()
                }
            }
        }
        if (this.gotoCloseTime > 0 && now >= this.gotoCloseTime) {
            this.gotoCloseTime = 0;
            this.close(true)
        }
    }

    private checkDestroyAccountConnect() {
        let isNeedDestroy: boolean = true
        for (const key in Config.ServerType_List) {
            let value: string = Config.ServerType_List[key]
            if (this.account.includes(value)) {
                this.isInternalServer = true
                isNeedDestroy = false
                break;
            }
        }
        if (isNeedDestroy) {
            Logger.log("NoMsg_Time_Inteval=22=", this.account)
            this.destroy()
        }
    }

    private checkConnection() {
        if (!this.connection) {
            this.destroy()
            return false;
        }
        else if (this.connection.readyState == SocketConnection.ReadyState.Close) {
            this.connection.terminate();
            this.destroy();
            return false;
        }
        return true;
    }


    public gotoClose() {
        this.isClosing = true;
        this.gotoCloseTime = DateUtil.now() + 1000;
        // if(this.player){
        //     this.player.toDbStr() //数据回写
        // }
    }

    private close(isForce: boolean = false) {
        if (this.connection.readyState == SocketConnection.ReadyState.Open || isForce) {
            this.connection.terminate();
            this.destroy();
        }
    }

    private onClientMsgHandler(data) {
        try {
            // Logger.info("onClientMsgHandler======data==", data);
            let byteArray: Uint8Array = new Uint8Array(data);
            let baseMsg: JhaoProto.BaseMsg = ProtoManager.instance.decode(JhaoProto.BaseMsg, byteArray)
            if (baseMsg.cmdIndex >= JhaoProto.CmdIndex.server_internal_None) { //服务器内部信息
                SocketClientMsgHandler.onEventSocketGata(this, baseMsg);
            } else {
                if (baseMsg.cmdOrder > 0) {
                    HallServer_SocketMsgHandler.onEventSocketGata(this, baseMsg)
                } else {   //服务器内部消息
                    // SocketClientMsgHandler.onEventSocketGata(this, baseMsg);
                }
            }
        } catch (error) {
            Logger.info("onClientMsgHandler======error==", error);
            Logger.error("onClientMsgHandler======error==", error);
            this.close(true)
        }
    }

    private createSendPack(baseMsg: JhaoProto.IBaseMsg) {
        return ProtoManager.instance.encode(JhaoProto.BaseMsg, baseMsg)
    }

    //单纯把错误信息发送给客户端
    public sendErrorToClient(cmdOrder: number, error_code: JhaoProto.ErrorCodeWs, errorMsg: string, cmdIndex: number = JhaoProto.CmdIndex.None) {
        let baseMsg: JhaoProto.IBaseMsg = {
            cmdIndex: cmdIndex,
            cmdOrder: cmdOrder,
            timeDownload: DateUtil.now(),
            errorCode: error_code,
            errorMsg: errorMsg,
        }
        this.sendMsgToClient(baseMsg);
    }

    public createMsgToClient(cmdIndex: number, cmdOrder: number, en_proto_ctor: any=null, data: any=null) {
        let baseMsg: JhaoProto.IBaseMsg = {
            cmdOrder: cmdOrder,
            cmdIndex: cmdIndex,
            timeDownload: DateUtil.now(),
        }
        if(en_proto_ctor && data){
            baseMsg.data =  ProtoManager.instance.encode(en_proto_ctor, data)
        }
        this.sendMsgToClient(baseMsg);
    }

    private sendMsgToClient(socketMsg: JhaoProto.IBaseMsg) {
        if (!this.checkConnection()) {
            return;
        }
        if (!this.isDestroyed) {
            this.connection.send(this.createSendPack(socketMsg));
        } else {
            Logger.error("sendMsgToClient=error=", this, socketMsg);
        }
    }


    public isLogin(): boolean {
        if (this.account && this.account != null && this.account != "") {
            return true
        } else {
            return false
        }
    }

    private async destroy() {
        if (!this.isDestroyed) {
            EventManager.instance.clear(this)
            Logger.log("socketconnection destroy=", this.account)
            this.isDestroyed = true;
            this.connection = null;
            this.account = null;
            if (this.user) {
                this.user.destroy()
            }
            this.user = null
            SocketConnectionManager.instance.removeSocketConnection(this);
        }
    }
}